package semantic.rules.postprocess


import scala.collection.mutable.Buffer
import semantic.CLabels._
import semantic.COperations._

object CPostProcessRuleWhile extends CPostProcessRule
{
    override def apply()(implicit code:Buffer[String]) =
    {
        val lblsWhlBgn = collection.mutable.HashMap[Long, Int]()
        val lblsWhlTrgt = collection.mutable.HashMap[Long, Int]()
        val lblsWhlGT = collection.mutable.HashMap[Long, Int]()
        val trm = if (code.headOption.exists(_.startsWith(LABEL_WHILE_BEGIN))) - 1 else 0

        def findLabels(from:Int = 0, i:Int = 0):Int =
        {
            if (i >= code.size) return i

            val ln = code(i)

            if (ln contains s"$LABEL_WHILE_BEGIN") lblsWhlBgn += extractID(ln) -> (i + 1 - from + trm)
            else if (ln startsWith s"$PUSH $LABEL_WHILE_TARGET") lblsWhlTrgt += extractID(ln) -> (i + 1 - from + trm)
            else if (ln startsWith s"$PUSH $LABEL_WHILE_GO_TO") lblsWhlGT += extractID(ln) -> (i + 2 - from + trm)

            if (ln startsWith FUNC) findLabels(from, findLabels(i + 1, i + 1))
            else if (ln startsWith END) i + 1
            else if (ln contains LABEL_WHILE_BEGIN) findLabels(from, i + 1)
            else findLabels(from, i + 1)
        }

        findLabels()

        code.foldLeft(0)((i, v) =>
        {
            if (v startsWith s"$PUSH $LABEL_WHILE_TARGET")
            {
                val id = extractID(v)
                code(i) = v replace (s"$LABEL_WHILE_TARGET$id", lblsWhlGT(id) toString)
            }
            else if (v startsWith s"$PUSH $LABEL_WHILE_GO_TO")
            {
                val id = extractID(v)
                code(i) = v replace (s"$LABEL_WHILE_GO_TO$id", lblsWhlBgn(id) toString)
            }
            i + 1
        })

        val fltrd = code map (s =>
            if (s contains LABEL_WHILE_BEGIN) s replace (s"$LABEL_WHILE_BEGIN${extractID(s)}", "") else s)
        code.clear()
        code ++= fltrd
    }

    private def extractID(string:String) = string substring ((string lastIndexOf LABEL_TERMINATOR) + 1) toLong
}
